package br.net.woodstock.tickettoride.web.jsf.manager.common;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;

import javax.faces.event.FacesEvent;
import javax.faces.model.SelectItem;

import br.net.woodstock.rockframework.utils.IOUtils;
import br.net.woodstock.rockframework.web.faces.utils.FacesUtils;
import br.net.woodstock.tickettoride.api.manager.ApplicationService;
import br.net.woodstock.tickettoride.api.manager.CertificateRequest;
import br.net.woodstock.tickettoride.api.manager.CertificateService;
import br.net.woodstock.tickettoride.client.utils.CodecUtils;
import br.net.woodstock.tickettoride.orm.Application;
import br.net.woodstock.tickettoride.orm.Certificate;
import br.net.woodstock.tickettoride.orm.UserType;
import br.net.woodstock.tickettoride.web.jsf.TTRBean;
import br.net.woodstock.tickettoride.web.jsf.security.common.JSFSecurityUtils;

public abstract class AbstractCertificateBean extends TTRBean {

	private static final long		serialVersionUID	= -7676757968836904361L;

	private static final String		STORE_FILE_NAME		= "mystore.pfx";

	private static final String		CERT_FILE_NAME		= "mycert.cer";

	private static final String		MAIN_VIEW			= "/manager/certificate.xhtml";

	private static final String		LIST_VIEW			= "/manager/certificate-list.xhtml";

	private static final String		SAVE_VIEW			= "/manager/certificate-save.xhtml";

	private static final String		UPLOAD_VIEW			= "/manager/certificate-upload.xhtml";

	private static final String		DETAIL_VIEW			= "/manager/certificate-detail.xhtml";

	private static final String		UPLOAD_PREFIX		= "cert";

	private static final String		UPLOAD_SUFFIX		= ".dat";

	private Integer					id;

	private Integer					applicationId;

	private String					alias;

	private String					subject;

	private String					issuer;

	private String					storePassword;

	private String					keyPassword;

	private String					view;

	private Certificate				certificate;

	private Application				application;

	private File					uploadedFile;

	private Collection<SelectItem>	applications;

	private Collection<Certificate>	certificates;

	public AbstractCertificateBean() {
		super();
		this.view = AbstractCertificateBean.LIST_VIEW;
	}

	public abstract ApplicationService getApplicationService();

	public abstract CertificateService getCertificateService();

	public String start() {
		this.onStart();
		if (JSFSecurityUtils.isUserInRole(UserType.ADMINISTRATOR.name())) {
			Collection<Application> collection = this.getApplicationService().listByFilter(null);
			this.applications = this.toSelectItem(collection);
		} else {
			Collection<Application> collection = this.getApplicationService().listByManager(JSFSecurityUtils.getSessionUser().getId(), null);
			this.applications = this.toSelectItem(collection);
		}
		this.applicationId = null;
		this.application = null;
		this.certificates = null;
		return AbstractCertificateBean.MAIN_VIEW;
	}

	public String end() {
		this.onEnd();
		return TTRBean.INDEX_VIEW;
	}

	public String newCertificate() {
		this.id = null;
		this.alias = null;
		this.subject = null;
		this.issuer = null;
		this.storePassword = null;
		this.keyPassword = null;
		this.view = AbstractCertificateBean.SAVE_VIEW;
		return null;
	}

	public String uploadCertificate() {
		this.view = AbstractCertificateBean.UPLOAD_VIEW;
		return null;
	}

	public String select() {
		this.application = this.getApplicationService().getById(this.applicationId);
		this.certificates = this.getCertificateService().listByApplication(this.applicationId);
		return null;
	}

	public String create() {
		CertificateRequest request = new CertificateRequest(this.applicationId, this.alias, this.subject, this.issuer, this.storePassword, this.keyPassword);
		Integer id = this.getCertificateService().create(request);
		this.id = id;
		this.certificate = this.getCertificateService().getById(id);
		this.view = AbstractCertificateBean.DETAIL_VIEW;
		return null;
	}

	public String upload() throws IOException {
		FileInputStream inputStream = new FileInputStream(this.uploadedFile);
		byte[] bytes = IOUtils.toByteArray(inputStream);
		inputStream.close();
		Integer id = this.getCertificateService().upload(this.applicationId, this.alias, bytes);
		this.id = id;
		this.certificate = this.getCertificateService().getById(id);
		this.view = AbstractCertificateBean.DETAIL_VIEW;
		return null;
	}

	public String show() {
		this.certificate = this.getCertificateService().getById(this.id);
		this.view = AbstractCertificateBean.DETAIL_VIEW;
		return null;
	}

	public String downloadPKCS12() throws IOException {
		byte[] base64 = this.certificate.getPkcs12();
		byte[] bytes = CodecUtils.fromBase64(base64);
		FacesUtils.download(bytes, AbstractCertificateBean.STORE_FILE_NAME);
		return null;
	}

	public String downloadCert() throws IOException {
		byte[] base64 = this.certificate.getData();
		byte[] bytes = CodecUtils.fromBase64(base64);
		FacesUtils.download(bytes, AbstractCertificateBean.CERT_FILE_NAME);
		return null;
	}

	public void uploadListener(final FacesEvent event) throws IOException {
		File file = File.createTempFile(AbstractCertificateBean.UPLOAD_PREFIX, AbstractCertificateBean.UPLOAD_SUFFIX);
		FileOutputStream outputStream = new FileOutputStream(file);
		outputStream.write(this.getBytesFromUpload(event));
		outputStream.close();

		this.uploadedFile = file;
	}

	public String cancel() {
		if (JSFSecurityUtils.isUserInRole(UserType.ADMINISTRATOR.name())) {
			Collection<Application> collection = this.getApplicationService().listByFilter(null);
			this.applications = this.toSelectItem(collection);
		} else {
			Collection<Application> collection = this.getApplicationService().listByManager(JSFSecurityUtils.getSessionUser().getId(), null);
			this.applications = this.toSelectItem(collection);
		}
		this.applicationId = null;
		this.application = null;
		this.certificates = null;
		this.uploadedFile = null;
		this.view = AbstractCertificateBean.LIST_VIEW;
		return null;
	}

	public String back() {
		this.select();
		this.view = AbstractCertificateBean.LIST_VIEW;
		return null;
	}

	protected abstract byte[] getBytesFromUpload(final FacesEvent event);

	private Collection<SelectItem> toSelectItem(final Collection<Application> collection) {
		if (collection == null) {
			return null;
		}
		Collection<SelectItem> items = new ArrayList<SelectItem>();
		for (Application a : collection) {
			items.add(new SelectItem(a.getId(), a.getName() + "(" + a.getAlias() + ")"));
		}
		return items;
	}

	// Getters and Setters
	public Integer getId() {
		return this.id;
	}

	public void setId(final Integer id) {
		this.id = id;
	}

	public Integer getApplicationId() {
		return this.applicationId;
	}

	public void setApplicationId(final Integer applicationId) {
		this.applicationId = applicationId;
	}

	public String getAlias() {
		return this.alias;
	}

	public void setAlias(final String alias) {
		this.alias = alias;
	}

	public String getSubject() {
		return this.subject;
	}

	public void setSubject(final String subject) {
		this.subject = subject;
	}

	public String getIssuer() {
		return this.issuer;
	}

	public void setIssuer(final String issuer) {
		this.issuer = issuer;
	}

	public String getStorePassword() {
		return this.storePassword;
	}

	public void setStorePassword(final String storePassword) {
		this.storePassword = storePassword;
	}

	public String getKeyPassword() {
		return this.keyPassword;
	}

	public void setKeyPassword(final String keyPassword) {
		this.keyPassword = keyPassword;
	}

	public void setView(final String view) {
		this.view = view;
	}

	public String getView() {
		return this.view;
	}

	public Certificate getCertificate() {
		return this.certificate;
	}

	public void setCertificate(final Certificate certificate) {
		this.certificate = certificate;
	}

	public Application getApplication() {
		return this.application;
	}

	public void setApplication(final Application application) {
		this.application = application;
	}

	public File getUploadedFile() {
		return this.uploadedFile;
	}

	public void setUploadedFile(final File uploadedFile) {
		this.uploadedFile = uploadedFile;
	}

	public Collection<SelectItem> getApplications() {
		return this.applications;
	}

	public void setApplications(final Collection<SelectItem> applications) {
		this.applications = applications;
	}

	public Collection<Certificate> getCertificates() {
		return this.certificates;
	}

	public void setCertificates(final Collection<Certificate> certificates) {
		this.certificates = certificates;
	}

}
